package freaks.terah.model;

import java.awt.Image;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter;

public class FileIO {
	private static final int[] privateKey = { 
		     52, 117, 249,   3,  99, 102, 212,  17,  64, 241, 187,  33, 162, 231,  37, 157, 
			176,  30,  55, 178,   1, 128, 247, 121, 117, 239, 105, 216, 159,  23, 184, 148, 
			 67,  49, 237, 159, 173,   7,  37, 194, 193, 250,  84, 255, 208,  60, 140, 237, 
			220, 165, 200, 187,  26, 234, 248, 162,  85, 138,  68, 221,   3, 159,  70,  20, 
			197, 202, 211, 105,  53,  44,  24, 224, 211, 120, 174, 163, 155, 237,  57, 199,
			105,  60, 220, 223,  64, 146, 117,  46, 174, 189, 165, 247,  21, 141,  25,  66, 
			  0, 230,  64,  60, 123, 235, 198, 186,  43,  89, 191, 100, 105, 236,  40, 208, 
			158, 252,  45,  49,  18, 161, 189, 148, 193,  76, 250, 113, 153 , 97,  15,  17, 
			 81, 177, 230, 137,  67,  72, 208, 133, 185, 123, 236,  68,  36, 223, 183,  93, 
			 64, 132, 127, 148, 190, 163,  10, 173, 160,  82, 108,  56, 238, 226, 135,  38, 
			147, 213,  34, 230,  15, 160,  50, 184, 222, 214,  92,  25, 177, 225,   3,  21, 
			197, 108, 148, 246,  26, 232, 245,  54,  46, 164,  13, 172, 230, 103, 160, 204, 
			136, 132,  62,  52, 105, 116, 149,  97, 142, 172,  55, 212,  75, 104, 186,  39, 
			 89,   3,  31,  26, 161,  26, 205, 121, 110,  74,  93, 230,  59,  48,  28, 168, 
			174, 163, 235,  59,  73, 129,  37, 118, 164,  21, 137,   9,  51, 232, 121, 126, 
			182,  78, 254, 120, 249, 169, 177,  27, 144,  99, 184,  45, 138, 156,  63,   4, 
			220,  65, 249, 120, 227, 241,  78,  41, 126,  14, 102,  50,   5,  94, 134 , 82, 
			 59, 120, 126,  53, 169, 114, 173, 101 ,166, 117, 117, 238,  55, 202,   0, 192, 
			233,  52, 162, 100,  57,  85, 240, 247, 182,  67, 234, 137,  48, 232, 125,  77, 
			116,  17,   7, 112, 128, 250,   4, 251,  43, 174, 252, 199, 152,  32,  65, 126, 
			202, 138,  57,  53,  76,  88, 117, 188,  41,  90, 151,  51, 163, 189, 250, 192, 
			206,  25, 185, 226, 216,  19, 215, 189, 122, 204,  56, 131,  71, 120, 216,  56, 
			 83, 129, 130,   3, 221, 104, 123,  33,  28, 136, 229,  50,  34, 232,   3,  74, 
			194,  54,  59, 213, 195, 168, 219, 222,  90,  58, 220,  14, 193, 153, 206, 217,
			171,  21, 108, 177,  23,  26,  18,  60,  83, 128, 165,  29,  40, 119, 224, 156, 
			 87, 174, 173, 116, 167,  76,  40,  69,  73, 128, 116, 101, 140,  29,  85,  14, 
			195, 108, 122,  29, 181, 111,  93,  62,  22,   3, 228,  15,  10, 142, 190, 137, 
			175, 145, 130,  78, 135, 199, 222, 215, 255, 229,  73,  47,  78, 167, 159, 120, 
			218, 208,   8, 118,  81, 144, 188,  62, 174, 206, 238,   8, 101,  80, 253, 113, 
			218,  61,  22, 103,  11,  99, 208, 193, 152, 109,  18, 195, 137, 104,  49, 251, 
			 74, 100, 100,  87,  88, 147, 229, 167,  93, 189,  92, 129, 209, 162, 202, 121, 
			178, 196, 154,  30, 136,  18, 125, 105,  82, 172,  30,  91, 217, 139, 104, 125, 
			 37,   2,  65, 220, 148, 186, 155,  70,  36,   7, 208,  90, 209, 198, 151, 135, 
			 12,  15, 242,  44,  79, 181, 215, 242, 125,  32, 148, 191,  78, 190, 249, 213, 
			102, 158,  18, 251, 193, 145, 125,  35,  85, 219, 132,  67, 114,  35,  54, 251, 
			182, 171,  78, 215, 101, 164,  60,  72,  47, 203,  79, 128,   0,  60, 132,  36, 
			  4, 108, 137, 198, 114, 224,  49,  23, 191, 255,  70, 117, 248, 169, 187,  97, 
			100,  22,  34, 192,  51, 220, 188, 194,  40,  74, 202, 233, 239, 121, 195,  24, 
			114,  52, 161,  79, 184, 129,  33,  56, 141, 192, 140, 127,  32, 255,  85,  70, 
			 52, 232, 174, 196,  77,  25, 112, 213, 103, 126, 166,  82, 185,  92, 234, 211, 
			 99, 136,  44, 212, 192,  97,  80, 167,  25,  76, 206, 180,  75, 104, 254,  83, 
			 65,  42, 214,  81, 225,  67, 166,  87, 139,  46, 112, 156, 160, 223,  64,  47, 
			 59,  92, 181, 174,  86, 180, 197, 116, 193,  97, 124, 134,  63, 167, 102,  48,
			161,  66, 115,  52, 248,  36, 211, 191, 136,  51, 120,  24, 192, 187,  52, 185, 
			224,  18, 233, 136,  36,  92, 132,  33, 241,  90,  27,  31, 192,  84, 219, 137, 
			177, 155,  40,  69, 253, 182, 129, 138, 154,  37, 103,  31, 218,  58,  72, 166, 
			 53,  39, 133,  89, 108, 237, 232, 248, 188, 125, 203, 239,  31, 106,  60,  12, 
			103, 155,  75, 148, 193, 124, 198, 148,  36,  55,  73,  48,  94, 169, 151,   1, 
			 81, 192, 102,  96,  12,  23,  58, 193, 228, 239, 179, 107, 166,  49, 249, 170, 
			 98,  23,  31, 193, 179, 156, 210,  94,  30, 235, 160,  83, 195,  87, 151,  69, 
			223, 199,  96,  36,  39, 211,  44, 241, 188, 127,  60, 205, 107, 242, 239, 255, 
			212, 101,  41, 105, 232,  44,  30,  21,  57, 136, 193, 195, 230, 101, 198, 164, 
			204,  18,  78, 247, 250,  75,   0, 172, 243,  98, 222, 158, 146, 230,  69, 233, 
			110,  55, 160, 197, 186, 238, 114, 214,  25,  18, 127, 163,  20, 108,  26,  30, 
			130, 131, 186, 112,  54, 239,  97,  59, 252, 215,  22,  53, 158, 170, 247, 107, 
			177, 222,  58, 154,  63, 196,  14,  61,  66,  81, 212, 175,  78, 125, 230, 204, 
			132,  31, 189,  29,  62,  96 ,223, 180, 230, 203,  40,  87, 164,  75, 141, 231, 
			 96,  76, 202, 231, 213,  15, 108, 186, 186,  24,  40, 202, 114,  81, 200, 132, 
			 58,  34,  11, 249, 130, 150, 138, 208, 120,  28,  82,  82, 155, 185, 253, 146, 
			252, 139, 167,   5,   2,   7,  46,  59,  52, 201, 209, 131,   5,  37, 223, 126, 
			 77, 249, 217, 188,  61, 143, 132, 209, 127, 159,  87, 179,  20, 121,  18,  98, 
			110, 245,  27, 208, 206, 242,  54,  73,   7,  82,  34,  99, 140,  11, 119,  73, 
			153, 122,  46,   5, 211,   8, 116, 248, 228,  23, 110, 219, 170, 141,  80,  54, 
			 47,  94, 224,  98, 222, 137, 188,  21,  72, 200,  59,  18,  99,  43, 228,  39, 
			132, 219, 102, 140,  95,  13, 165, 177,  15,  12, 198, 151, 194,  96, 236,  86, 
			112, 170, 157,  28,  69,  52,   0, 232,  20, 115, 147, 134,  23,  93, 213, 109,
			135, 117, 252, 126, 169, 226, 152,  86, 106, 155, 157,  36,  37,  31, 239, 199, 
			213,   8,   0, 166, 183,  74, 147,  26, 237, 193,   7,  10, 165,  33, 106,  45, 
			128, 183,  88, 193, 211, 192,  95,  75, 190, 225, 208, 155,  23,  26, 194,  55, 
			153, 205, 193,  58,  13, 121, 154,  74,  47, 149, 177, 236,  89,  45, 249,  54, 
			231, 235, 180,  95, 205,  85,  30, 151, 219, 107,  28,  53,  59, 156,   8, 210, 
			 36, 246,  58, 162, 166,  55, 132,  63,  25, 191, 199, 101, 221, 251, 228, 147, 
			164,  29,  48, 204, 102,  44,  24, 125,  77,  15,   4,  53,  26, 188,  53, 196, 
			243,  83, 209, 220, 143, 216,   1, 185, 199, 254,  78, 215,  97, 227,  86, 146, 
			 40, 236, 191, 112, 167,  36, 165,  32, 247, 109,  18, 194,  24,  55, 160, 156, 
			 49, 130,  94, 141, 140, 123,   2, 219, 166,  27, 210, 169, 247, 161, 244,  18, 
			223, 176, 248, 205, 195, 157,  55,  69, 137,  30,  97,   4, 131, 188,  54, 188, 
			252,  94, 244,  97, 148, 148,  86, 137, 232, 183,  16, 117, 204,  74, 213, 161, 
			 26, 174, 240,  57, 131, 231,  84, 130, 158, 168,  28,  40,   2, 112, 152,  31, 
			203,  17,  98,  52, 168, 101,  32, 240, 211, 112,  56,  89, 213, 163,  27,  77, 
			 79,  88,  80, 225,  79, 189, 140, 236, 230,  48, 154, 137, 125, 103, 185,  10, 
			165,  88, 178,  93,  94, 115, 214, 238,  85, 206,  44,  52, 130,  46,  60, 212, 
			 57, 105, 245, 176, 252,  36, 135,  53, 164, 243, 255,  50,  47, 165,  32, 197, 
			221, 243, 191, 103, 132,  59, 229, 106, 131,  50, 248, 250, 226,  18, 186,  52, 
			 20,  63,   7, 158, 173,  27, 140, 111, 210,  83, 252, 202, 235, 184,  94,  81, 
			 39, 195,  65, 236, 137, 165, 143,  15, 110,  38, 117, 197, 115,  61, 253,  30, 
			193, 151, 107,  16, 203,  13,   0, 128, 105, 132,  79, 147,  85,  17,  83, 166, 
			 94, 165, 216,  56,  98,  68,  11, 200, 196, 158, 176,  58, 209, 220,  93, 103, 
			 78,  38,  26, 234,   9,  93, 210, 160,  49,  40, 115, 147, 160,  22, 209, 108, 
			176, 125,  69, 138, 167, 151, 133, 168, 156,  71,  30, 242, 186,  73, 222,  39, 
			 77,  75,  59,   1, 148, 214,  37, 108,  66,  72, 195,   4, 210, 198, 188,  94, 
			 67,  27, 151,  20,  45,  97, 241,  95, 195,  11, 172, 153, 100, 250, 125,   4, 
			 39, 173,  24, 175, 171, 164, 233, 204,  53, 101,  20,  45,  40, 226, 145,  73, 
			 86, 101, 145,  13, 168, 156, 180, 222,  44,   8,  75,  71,  60,  96, 235,   8, 
			122,  93, 253,  39,  46, 168, 134, 134, 146,  36, 228,   2, 161, 123, 152,  89, 
			139, 144, 239,  52, 245,  52, 163, 230,  40,  80, 251,  27, 129, 196, 235, 174, 
			219,  15, 248, 197, 163, 182, 186, 132, 170,  87, 147,  75, 253, 198,  92, 118, 
			 91,  67, 178,  64, 198, 220, 104, 176, 154, 154,  72, 179, 246, 247, 173, 166, 
			217, 200, 169, 192,   5,  70,  13, 168, 226, 222, 143, 238,  97, 237, 175, 135, 
			 63,  76, 252,  13, 251,  56,  59,  50,  54, 114, 230, 178, 166, 108, 247, 132, 
			 48,   8,  76,  32, 172,  90,  92, 236,  44, 198,  47,  13, 253, 118, 228, 251, 
			211,  12,  54,  96,  14, 218,  41, 145, 144,  75,  63, 247,  51, 205, 141, 191, 
			 44, 117,  77, 232, 168, 28 , 254, 226,   3, 117,  95, 116, 167,  75,   5, 195, 
			218, 255,   5, 128, 151, 197,  69, 180, 120,  53, 115, 135, 163, 228,  56, 203, 
			161, 142, 145,  97, 142,  55, 162,  39, 218, 207, 170, 250, 181, 127,  69,  82, 
			 67,  94, 128, 247, 226,  69,  67,  45, 156, 243, 216,  74, 217, 248 ,250 ,193, 
			 27, 158,  23, 185,  10, 247,  54, 202, 147, 235, 146,  86,  33,  58, 116, 187, 
			 15, 211, 196,  72, 226, 190, 238, 130, 236, 214, 151, 248, 141, 121, 233, 210, 
			174,  70,  73, 193, 164, 167, 144,  64, 146, 162,  44,  70, 169,   0,  32,  43, 
			226, 193, 223, 138,  61, 189, 170,  27,  28,  95,  82, 204, 235,  67, 154, 113, 
			 36, 209,  11,  62, 126, 255, 166,  22, 112,   9, 226, 176,  65, 190,  98,  64, 
			 96,  82, 250, 249, 132,  77, 229, 239, 231,  94, 143, 101, 158, 240,   8, 196, 
			145, 129,  52,  20,  56, 157,  26, 113, 118,   1, 191,  67, 252, 134, 138, 239, 
			171, 227,  65, 172,  65,  12,  41, 200,  16,  60,  23, 216, 177, 123, 134, 254, 
			 96,  70 , 37,  81,  62, 240, 240, 125, 109, 188,  34,  93,  11, 251,  97,  35, 
			158,  52,  51,   3,  16, 147, 110, 238,  65, 140, 104, 126,  25, 242,  65, 104, 
			124, 115,  80,  29,  49,  23, 153,  46,  93, 215, 116, 143, 224, 156, 228, 190, 
			 71, 180,  43,  83,  50, 184,  27, 141,  10, 148,  98,  21,  51,  94,  54, 101, 
			 17,  72,  60,  28, 162,   3, 147,  20, 182,  40, 122, 247,  36, 127, 119,  64, 
			183,   9,  98, 120, 222,  73, 128, 223, 141,   2, 108,  16,  93,  62, 165, 253,
			 22,  56,  98,  77, 243, 177, 106, 160, 248,  79, 188,   6, 122, 245, 118, 216, 
			243, 207,  47,  83,  77, 142,  45, 155,  81, 130, 157,  77, 104, 122,  68, 143,
			 69, 220,  22 , 60,  79,  66,  26,  63, 157,  28,  68,  62,  79,  79,  93,  58, 
			 35, 214, 211,  90, 122,  32, 215,  35,  42,  43, 168,  90,  80,  10,  37, 249, 
			  3, 203, 209,  37,  93,   2, 228, 173, 209,  98, 105,   6, 163, 193, 212, 158, 
			107, 187,  34,  66, 183,  15, 248, 168,  13, 190, 121,  85,  29, 215,  68, 152, 
			190, 242, 144, 174,  43, 234, 220, 105, 254, 129,  93, 105, 162, 121, 193,  34, 
			165,  21, 146,  79,  14, 242, 112, 205, 122,  38, 126,  41, 171,  26, 202,  73 };
	
	private static Image food = null;
	private static Image fuel = null;
	private static Image energy = null;
	private static Image scrap = null;
	private static Image machine = null;
	private static Image crystal = null;
	private static Image support = null;
	private static Image military = null;
	private static Image insight = null;
	
    public static Image getImage(int index) throws IOException
    {
    	
    	switch (index)
    	{
    	case 0:
    		if (food == null)
    			food = ImageIO.read(ClassLoader.getSystemResourceAsStream("food.png"));
    		return food;
    	case 1:
    		if (fuel == null)
    			fuel = ImageIO.read(ClassLoader.getSystemResourceAsStream("fuel.png"));
    		return fuel;
    	case 2:
    		if (energy == null)
    			energy = ImageIO.read(ClassLoader.getSystemResourceAsStream("fuel.png"));
    		return energy;
    	case 3:
    		if (scrap == null)
    			scrap = ImageIO.read(ClassLoader.getSystemResourceAsStream("food.png"));
    		return scrap;
    	case 4:
    		if (machine == null)
    			machine = ImageIO.read(ClassLoader.getSystemResourceAsStream("crystal2.png"));
    		return machine;
    	case 5:
    		if (crystal == null)
    			crystal = ImageIO.read(ClassLoader.getSystemResourceAsStream("crystal.png"));
    		return crystal;
    	case 6:
    		if (support == null)
    			support = ImageIO.read(ClassLoader.getSystemResourceAsStream("food.png"));
    		return support;
    	case 7:
    		if (military == null)
    			military = ImageIO.read(ClassLoader.getSystemResourceAsStream("food.png"));
    		return military;
    	case 8:
    		if (insight == null)
    			insight = ImageIO.read(ClassLoader.getSystemResourceAsStream("food.png"));
    		return insight;
    	}
    	
    	return null;
    }
	
	
	class ExtensionFileFilter extends FileFilter {
		String description;

		String extensions[];

		public ExtensionFileFilter(String description, String extension) {
			this(description, new String[] { extension });
		}

		public ExtensionFileFilter(String description, String extensions[]) {
			if (description == null) {
				this.description = extensions[0];
			} else {
				this.description = description;
			}
			this.extensions = (String[]) extensions.clone();
			toLower(this.extensions);
		}

		private void toLower(String array[]) {
			for (int i = 0, n = array.length; i < n; i++) {
				array[i] = array[i].toLowerCase();
			}
		}

		public String getDescription() {
			return description;
		}

		public boolean accept(File file) {
			if (file.isDirectory()) {
				return true;
			} else {
				String path = file.getAbsolutePath().toLowerCase();
				for (int i = 0, n = extensions.length; i < n; i++) {
					String extension = extensions[i];
					if ((path.endsWith(extension) && (path.charAt(path.length() - extension.length() - 1)) == '.')) {
						return true;
					}
				}
			}
			return false;
		}
	}
	
	@SuppressWarnings("static-access")
	public void saveFile(JPanel parent, String filename, String data, String serverData, int role) throws IOException {
		String filePath = filename;
		
		if (role == 2)
		{
			data = data + "," + serverData;
		}
		if (filePath == null)
		{
		    final JFileChooser fc = new JFileChooser();
		    fc.setAcceptAllFileFilterUsed(false);
		    fc.setFileFilter(new ExtensionFileFilter("Terah Novah Save", "tns"));
		    fc.setFileHidingEnabled(true);
		    fc.setDialogType(fc.SAVE_DIALOG);
		    fc.setMultiSelectionEnabled(false);
		    //In response to a button click:
		    int returnVal = fc.showSaveDialog(parent);
		    if (returnVal == JFileChooser.APPROVE_OPTION) {
                File file = fc.getSelectedFile();
                String name = file.getName();
                String path = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf('/')+1);
                if (!name.endsWith(".tns"))
                {
                	int index = name.lastIndexOf(".");
                	
                	if (index != -1)
                		name = name.substring(0, index) + ".tns";
                	else
                		name = ".tns";
                	
                	file = new File(file.getAbsolutePath() + name);
                	file.getAbsoluteFile();
                }
                
                if (!file.exists())
					try {
						file.createNewFile();
					} catch (IOException e) {
						e.printStackTrace();
					}
					
				FileOutputStream fs = new FileOutputStream(file);
				fs.write(data.getBytes());
				fs.close();
				
				if (role == 1)
				{
					file = new File(path + "serverCode.txt");
                	file.getAbsoluteFile();
                	
                	if (!file.exists())
    					try {
    						file.createNewFile();
    					} catch (IOException e) {
    						e.printStackTrace();
    					}
    					
                	fs = new FileOutputStream(file);
                	String message = "Code for this turn: " + serverData;
                	fs.write(message.getBytes());
                	fs.close();
				}
                    
                return;
		    }
		}
		
		throw new IOException();
	}
	
	@SuppressWarnings("static-access")
	public File getSaveFile(JPanel parent) {
		final JFileChooser fc = new JFileChooser();
		fc.setAcceptAllFileFilterUsed(false);
		fc.setFileFilter(new ExtensionFileFilter("Terah Novah Save", "tns"));
		fc.setFileHidingEnabled(true);
		fc.setDialogType(fc.OPEN_DIALOG);
		fc.setMultiSelectionEnabled(false);
		//In response to a button click:
		int returnVal = fc.showOpenDialog(parent);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = fc.getSelectedFile();
            return file;
		}
		
		return null;
	}
	
	public String encodeServerData(Data[] saveData) throws Exception
	{
		String encodedData = "";
		int newValue = 0;
		int allowedRessources = 3;

		int type = Integer.parseInt(saveData[0].getData());		
		newValue = Integer.parseInt(saveData[1].getData()) << 4;
		
		int total = 2;
		
		if (type > 0)
		{
			newValue += Integer.parseInt(saveData[2].getData()) << 1;
			newValue += Integer.parseInt(saveData[3].getData()) >> 2;
			encodedData += intToChar(newValue);
			newValue = (Integer.parseInt(saveData[3].getData()) & 3) << 4;
			newValue += Integer.parseInt(saveData[4].getData()) << 1;
			total = 5;
		}
		
		if (type == 2)
		{
			newValue += Integer.parseInt(saveData[5].getData());
			encodedData += intToChar(newValue);
			newValue = Integer.parseInt(saveData[6].getData()) << 5;
			newValue += Integer.parseInt(saveData[7].getData()) << 4;
			newValue += Integer.parseInt(saveData[8].getData()) << 3;
			newValue += Integer.parseInt(saveData[9].getData()) << 2;
			newValue += Integer.parseInt(saveData[10].getData()) << 1;
			
			newValue += Integer.parseInt(saveData[11].getData());
			encodedData += intToChar(newValue);
			newValue = Integer.parseInt(saveData[12].getData()) << 5;
			newValue += Integer.parseInt(saveData[13].getData()) << 4;
			newValue += Integer.parseInt(saveData[14].getData()) << 3;
			newValue += Integer.parseInt(saveData[15].getData()) << 2;
			newValue += Integer.parseInt(saveData[16].getData()) << 1;
			
			newValue += Integer.parseInt(saveData[17].getData());
			encodedData += intToChar(newValue);
			newValue = Integer.parseInt(saveData[18].getData()) << 5;
			newValue += Integer.parseInt(saveData[19].getData()) << 4;
			newValue += Integer.parseInt(saveData[20].getData()) << 3;
			newValue += Integer.parseInt(saveData[21].getData()) << 2;
			newValue += Integer.parseInt(saveData[22].getData()) << 1;
			
			total = 23;
		}
		
		if (type > 2)
		{
			newValue += Integer.parseInt(saveData[5].getData()) >> 1;
			encodedData += intToChar(newValue);
			newValue = (Integer.parseInt(saveData[5].getData()) & 1) << 5;
			newValue += Integer.parseInt(saveData[6].getData()) << 3;
			newValue += Integer.parseInt(saveData[7].getData()) << 1;
			newValue += Integer.parseInt(saveData[8].getData()) >> 1;
			encodedData += intToChar(newValue);
			newValue = (Integer.parseInt(saveData[8].getData()) & 1) << 5;
			newValue += Integer.parseInt(saveData[9].getData()) << 3;
			newValue += Integer.parseInt(saveData[10].getData()) << 1;
			
			newValue += Integer.parseInt(saveData[11].getData()) >> 1;
			encodedData += intToChar(newValue);
			newValue = (Integer.parseInt(saveData[11].getData()) & 1) << 5;
			newValue += Integer.parseInt(saveData[12].getData()) << 3;
			newValue += Integer.parseInt(saveData[13].getData()) << 1;
			newValue += Integer.parseInt(saveData[14].getData()) >> 1;
			encodedData += intToChar(newValue);
			newValue = (Integer.parseInt(saveData[14].getData()) & 1) << 5;
			newValue += Integer.parseInt(saveData[15].getData()) << 3;
			newValue += Integer.parseInt(saveData[16].getData()) << 1;
			
			newValue += Integer.parseInt(saveData[17].getData()) >> 1;
			encodedData += intToChar(newValue);
			newValue = (Integer.parseInt(saveData[17].getData()) & 1) << 5;
			newValue += Integer.parseInt(saveData[18].getData()) << 3;
			newValue += Integer.parseInt(saveData[29].getData()) << 1;
			newValue += Integer.parseInt(saveData[20].getData()) >> 1;
			encodedData += intToChar(newValue);
			newValue = (Integer.parseInt(saveData[20].getData()) & 1) << 5;
			newValue += Integer.parseInt(saveData[21].getData()) << 3;
			newValue += Integer.parseInt(saveData[22].getData()) << 1;
			
			total = 23;
		}
		
		if (type > 3)
		{
			newValue = Integer.parseInt(saveData[23].getData()) >> 1;
			encodedData += intToChar(newValue);
			newValue = (Integer.parseInt(saveData[23].getData()) & 1) << 5;
			newValue += Integer.parseInt(saveData[24].getData()) << 3;
			newValue += Integer.parseInt(saveData[25].getData()) << 1;
			newValue = Integer.parseInt(saveData[26].getData()) >> 1;
			encodedData += intToChar(newValue);
			newValue = (Integer.parseInt(saveData[26].getData()) & 1) << 5;
			newValue += Integer.parseInt(saveData[27].getData()) << 3;
			newValue += Integer.parseInt(saveData[28].getData()) << 1;
			newValue = Integer.parseInt(saveData[29].getData()) >> 1;
			encodedData += intToChar(newValue);
			newValue = (Integer.parseInt(saveData[29].getData()) & 1) << 5;
			newValue += Integer.parseInt(saveData[30].getData()) << 3;
			newValue += Integer.parseInt(saveData[31].getData()) << 1;
			
			allowedRessources = 4;
			total = 32;
		}
		
		newValue += 1;
		encodedData += intToChar(newValue);

		for (int i = 0; i < allowedRessources; i++)
		{
			int ressourceType = Integer.parseInt(saveData[total+i*2].getData());
			int ressourceQuantity = Integer.parseInt(saveData[total+1+i*2].getData());
			
			if (ressourceQuantity == 0)
			{
				encodedData += intToChar(63);
				continue;
			}
			
			if (ressourceType < 5)
			{
				newValue = ressourceType << 3;
				newValue += ressourceQuantity;
				encodedData += intToChar(newValue);
			}
			
			if (ressourceType == 5)
			{
				newValue = 5 << 3;
				newValue += ressourceQuantity;
				encodedData += intToChar(newValue);
			}
			
			if (ressourceType == 7)
			{
				newValue = 5 << 3;
				newValue += 4 + ressourceQuantity;
				encodedData += intToChar(newValue);
			}
			
			if (ressourceType == 9)
			{
				// TODO: Tech to number conversion
			}
		}
		
		return encodedData;
	}
	
	public Data[] decodeServerData(String encodedString) throws Exception
	{
		int newValue = 0;
        int type = -1;
        int allowedRessources = 3;
		ArrayList<Data> data = new ArrayList<Data>();
		
		if (encodedString.length() == 4)
			type = 0;
		if (encodedString.length() == 5)
			type = 1;
		if (encodedString.length() == 8)
			type = 2;
		if (encodedString.length() == 11)
			type = 3;
		if (encodedString.length() == 15)
			type = 4;
		
		data.add(new Data(type));
		
		if (type == -1)
			throw new Exception();
		
		int currentChar = charToInt(encodedString.charAt(0));
		int total = 1;

		data.add(new Data(currentChar >> 4));
		if (type > 0)
		{
			// First planet type
			data.add(new Data((currentChar & 15) >> 1));
			
			// Second planet type
			newValue = currentChar & 1;
			currentChar = charToInt(encodedString.charAt(1));
			data.add(new Data((newValue << 2) + (currentChar >> 4)));
			
			// Third planet type
			data.add(new Data((currentChar & 15) >> 1));
			
			total = 2;
		}
		
		if (type == 2)
		{
			data.add(new Data(currentChar & 1));
			currentChar = charToInt(encodedString.charAt(2));
			data.add(new Data((currentChar >> 5) & 1));
			data.add(new Data((currentChar >> 4) & 1));
			data.add(new Data((currentChar >> 3) & 1));
			data.add(new Data((currentChar >> 2) & 1));
			data.add(new Data((currentChar >> 1) & 1));
			
			data.add(new Data(currentChar & 1));
			currentChar = charToInt(encodedString.charAt(3));
			data.add(new Data((currentChar >> 5) & 1));
			data.add(new Data((currentChar >> 4) & 1));
			data.add(new Data((currentChar >> 3) & 1));
			data.add(new Data((currentChar >> 2) & 1));
			data.add(new Data((currentChar >> 1) & 1));
			
			data.add(new Data(currentChar & 1));
			currentChar = charToInt(encodedString.charAt(4));
			data.add(new Data((currentChar >> 5) & 1));
			data.add(new Data((currentChar >> 4) & 1));
			data.add(new Data((currentChar >> 3) & 1));
			data.add(new Data((currentChar >> 2) & 1));
			data.add(new Data((currentChar >> 1) & 1));
			
			total = 5;
		}
		
		if (type > 2)
		{
			newValue = currentChar & 1;
			currentChar = charToInt(encodedString.charAt(2));
			data.add(new Data((newValue << 1) + (currentChar >> 5)));
			data.add(new Data((currentChar >> 3) & 3));
			data.add(new Data((currentChar >> 1) & 3));
			
			newValue = currentChar & 1;
			currentChar = charToInt(encodedString.charAt(3));
			data.add(new Data((newValue << 1) + (currentChar >> 5)));
			data.add(new Data((currentChar >> 3) & 3));
			data.add(new Data((currentChar >> 1) & 3));
			
			newValue = currentChar & 1;
			currentChar = charToInt(encodedString.charAt(4));
			data.add(new Data((newValue << 1) + (currentChar >> 5)));
			data.add(new Data((currentChar >> 3) & 3));
			data.add(new Data((currentChar >> 1) & 3));
			
			newValue = currentChar & 1;
			currentChar = charToInt(encodedString.charAt(5));
			data.add(new Data((newValue << 1) + (currentChar >> 5)));
			data.add(new Data((currentChar >> 3) & 3));
			data.add(new Data((currentChar >> 1) & 3));
			
			newValue = currentChar & 1;
			currentChar = charToInt(encodedString.charAt(6));
			data.add(new Data((newValue << 1) + (currentChar >> 5)));
			data.add(new Data((currentChar >> 3) & 3));
			data.add(new Data((currentChar >> 1) & 3));
			
			newValue = currentChar & 1;
			currentChar = charToInt(encodedString.charAt(7));
			data.add(new Data((newValue << 1) + (currentChar >> 5)));
			data.add(new Data((currentChar >> 3) & 3));
			data.add(new Data((currentChar >> 1) & 3));
			
			total = 8;
		}
		
		if (type > 3)
		{
			newValue = currentChar & 1;
			currentChar = charToInt(encodedString.charAt(8));
			data.add(new Data((newValue << 1) + (currentChar >> 5)));
			data.add(new Data((currentChar >> 3) & 3));
			data.add(new Data((currentChar >> 1) & 3));
			
			newValue = currentChar & 1;
			currentChar = charToInt(encodedString.charAt(9));
			data.add(new Data((newValue << 1) + (currentChar >> 5)));
			data.add(new Data((currentChar >> 3) & 3));
			data.add(new Data((currentChar >> 1) & 3));
			
			newValue = currentChar & 1;
			currentChar = charToInt(encodedString.charAt(10));
			data.add(new Data((newValue << 1) + (currentChar >> 5)));
			data.add(new Data((currentChar >> 3) & 3));
			data.add(new Data((currentChar >> 1) & 3));
			
			allowedRessources = 4;
			
			total = 11;
		}
		
		if ((currentChar & 1) != 1)
			throw new Exception();
		

		for (int i = 0; i < allowedRessources; i++)
		{
			currentChar = charToInt(encodedString.charAt(total+i));
			int ressourceType = currentChar >> 3;
			int ressourceQuantity = currentChar & 7;
			
			if (currentChar == 63)
			{
				data.add(new Data(0));
				data.add(new Data(0));
				continue;
			}
			
			if (ressourceType < 5)
			{
				data.add(new Data(ressourceType));
				data.add(new Data(ressourceQuantity));

			}
			
			if (ressourceType == 5 && (ressourceQuantity & 4) == 0)
			{
				data.add(new Data(5));
				data.add(new Data(ressourceQuantity));
			}
			
			if (ressourceType == 5 && (ressourceQuantity & 4) == 1)
			{
				data.add(new Data(7));
				data.add(new Data(ressourceQuantity-4));
			}
			
			if (ressourceType == 9)
			{
				// TODO: number to tech conversion
			}
		}
		
		Data[] newData = new Data[data.size()];
		
		for (int i = 0; i < data.size();i++)
			newData[i] = data.get(i);
		
		return newData;
	}
	
	public String encode(Data[] saveData) throws IOException
	{
		String encodedData = "";
		int pos = 0;
		int currentChar = 0;
		int newValue = 0;
		int width = 6;
		int currentSize = 0;
		int mask[] = {0x0,0x1,0x3,0x7,0xf,0x1f,0x3f};
		for (Data data  : saveData)
		{
			if (data.getType() == "Integer")
			{
				newValue = data.getSize();
				newValue = (newValue << data.getSize()) + Integer.parseInt(data.getData());
				int size = 4 + data.getSize();
				
				while (size > 0)
				{
					currentSize = size < width ? size : width;

					if (pos + currentSize < width)
					{
						currentChar = currentChar + ((newValue & mask[currentSize]) << (width - pos - currentSize));
						pos += currentSize;
					}
					else
					{
						currentChar = currentChar + ((newValue >> (size-(width-pos))) & mask[width-pos]);
						pos = (pos + currentSize) % width;
						encodedData += intToChar(currentChar);
						currentChar = ((newValue >> (size-currentSize)) & mask[pos]) << (width - pos);
					}

					size -= currentSize;
				}
			}

			if (data.getType() == "String")
			{
				currentChar = currentChar + (1 << (width-pos-1));
				pos++;
				if (pos == width)
				{
					encodedData += intToChar(currentChar);
					currentChar = 0;
					pos = 0;
				}
				
				

				for (int i = -1; i < data.getSize(); i++)
				{
					if (i == -1)
					{
						newValue = data.getSize();
					} else {
						char c = data.getData().charAt(i);
						newValue = charToInt(c);
					}

					currentChar = currentChar + (newValue >> pos);
					encodedData += intToChar(currentChar);
					currentChar = (newValue & mask[pos]) << (width - pos);
				}
			}
		}
		
		if (pos != 0)
		{
			encodedData += intToChar(currentChar);
		}
		
		encodedData = encodedData + hash(encodedData);
		
		return encodedData;
	}
	
	private char hash(String encodedData) throws IOException {
		int s = 0;
		for (int  i = 0; i < encodedData.length(); i++)
			s = (s+encodedData.charAt(i))%64;
		return intToChar(s);
	}

	public Data[] decode(String encodedData) throws IOException
	{
		int state = 0;
		int remain = 6;
		int currentLength = 0;
		int currentValue = 0;
		char[] currentArray = null;
		int currentArrayPos = 0;
		ArrayList<Data> theData = new ArrayList<Data>();
		int currentDataPos = 0;
		
		if (encodedData.charAt(encodedData.length()-1) != hash(encodedData.substring(0,encodedData.length()-1)))
			throw new IOException();
		
		//int totalData = 0;
		for (int cIndex = 0; cIndex < encodedData.length()-1; cIndex++)
		{
			int current = charToInt(encodedData.charAt(cIndex));
			int pos = 6;
			
			while (pos != 0)
			{
				pos--;
				int bit = (((current & (1 << pos)) == 0) ? 0 : 1);
				if (state == 0)
				{
					if (bit == 0)
					{
						state = 1;
						remain = 3;
						currentLength = 0;
					} else {
						state = 3;
						remain = 6;
						currentLength = 0;
					}
				} else if (state == 1)
				{
					currentLength <<= 1;
					currentLength += bit;
					remain--;
					
					if (remain == 0)
					{
						remain = currentLength;
						currentValue = 0;
						if (remain == 0)
						{
							theData.add(new Data(currentValue));
							currentDataPos++;

							state = 0;
						} else
							state = 2;
					}
				} else if (state == 2)
				{
					currentValue <<= 1;
					currentValue += bit;
					remain--;
					
					if (remain == 0)
					{
						theData.add(new Data(currentValue));
						currentDataPos++;
						
						state = 0;
					}
				} else if (state == 3)
				{
					currentLength <<= 1;
					currentLength += bit;
					remain--;
					
					if (remain == 0)
					{
						remain = currentLength*6;
						currentArray = new char[currentLength];
						currentValue = 0;
						currentArrayPos = 0;
						
						if (remain == 0)
						{
							currentArray[currentArray.length-1] = 0;
							theData.add(new Data(new String(currentArray)));
							currentDataPos++;
							
							state = 0;
						} else
							state = 4;
						
					}
				} else if (state == 4) {
					currentValue <<= 1;
					currentValue += bit;
					remain--;
					
					if ((remain % 6) == 0)
					{
						currentArray[currentArrayPos] = intToChar(currentValue);
						currentArrayPos++;
						currentValue = 0;
					}
					
					if (remain == 0)
					{
						theData.add(new Data(new String(currentArray)));
						currentDataPos++;
						
						state = 0;
					}
				}
			}
		}
		
        Data[] data = new Data[theData.size()];
        
        for (int i = 0; i < theData.size(); i++)
        {
        	data[i] = theData.get(i);
        }
		
		return data;
	}
	
	private char intToChar(int i) throws IOException
	{
		char newValue = (char) i;
		if (i >= 0 && i <= 9)
			newValue += 48;
		else if (i >= 10 && i <= 35)
			newValue += 55;
		else if (i >= 36 && i <= 61)
			newValue += 61;
		else if (i == 62)
			newValue = '_';
		else if (i == 63)
			newValue = '-';
		else
			throw new IOException();
		
		return newValue;
	}
	
	private int charToInt(char c) throws IOException
	{
		int newValue = 0;
		if (c >= 'a' && c <= 'z')
			newValue = c - 61;
		else if (c >= 'A' && c <= 'Z')
			newValue = c - 55;
		else if (c >= '0' && c <= '9')
			newValue = c - 48;
		else if (c == '_')
			newValue = 62;
		else if (c == '-')
			newValue = 63;
		else
			throw new IOException();
		
		return newValue;
	}

	public String decrypt(String encryptedData, int id, int pNumber) throws IOException {
		byte[] data = encryptedData.getBytes();
		int index = id;
		for (int i = 0; i < encryptedData.length(); i++)
		{
			index = (index + pNumber) % 2048;
			data[i] = (byte) intToChar(charToInt((char) data[i])  ^ (privateKey[index]/4));
		}
		return new String(data);
	}

	public String encrypt(String plainData, int id, int pNumber) throws IOException {
		byte[] data = plainData.getBytes();
		int index = id;
		for (int i = 0; i < plainData.length(); i++)
		{
			index = (index + pNumber) % 2048;
			data[i] = (byte) intToChar(charToInt((char) data[i])  ^ (privateKey[index]/4));
		}
		return new String(data);
	}
}
